package cn.kgc.itrip.auth.service.impl;

import cn.kgc.itrip.auth.service.TokenService;
import cn.kgc.itrip.beans.pojo.ItripUser;
import cn.kgc.itrip.beans.vo.userinfo.ItripUserTokenVO;
import cn.kgc.itrip.utils.EmptyUtils;
import cn.kgc.itrip.utils.MD5;
import cn.kgc.itrip.utils.RedisAPI;
import cn.kgc.itrip.utils.UserAgentUtil;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Set;

@Service
public class TokenServiceImpl implements TokenService {

    private final String TOKEN_PC_PREFIX = "PC-";
    private final String TOKEN_MOBILE_PREFIX = "MOBILE-";
    @Resource
    private RedisAPI redisAPI;

    public Set<String> checkTokenKeyExists(ItripUser itripUser,String userAgent){
        StringBuffer tokenStrBuffer = new StringBuffer();
        // 检查是PC端还是移动端
        if(UserAgentUtil.CheckAgent(userAgent)){
            tokenStrBuffer.append(TOKEN_MOBILE_PREFIX);
        }else{
            tokenStrBuffer.append(TOKEN_PC_PREFIX);
        }
        // 加密UserCode
        tokenStrBuffer.append(MD5.getMd5(itripUser.getUserCode(),16)+"-");
        // 用户ID
        tokenStrBuffer.append(itripUser.getId()+"-");
        Set<String> keys = redisAPI.keys(TOKEN_KEY_PREFIX + tokenStrBuffer.toString() + "*");
        return keys;
    }

    @Override
    public void delToken(String token) throws Exception {
        if(redisAPI.exist(TOKEN_KEY_PREFIX+token)){
            redisAPI.delete(TOKEN_KEY_PREFIX+token);
        }
    }

    @Override
    public String refreshToken(String token, String userAgent, ItripUser currentUser) throws Exception {
        if(!redisAPI.exist(TOKEN_KEY_PREFIX+token)){
            throw new Exception("Token已经过期！");
        }
        // 置换Token
        String newToken = genToken(currentUser, userAgent);
        // 保存新Token
        saveTokenWithoutDel(newToken,currentUser,userAgent);
        // 缓存老Token 防止并发的请求携带的老Token无法被使用
        redisAPI.set(TOKEN_KEY_PREFIX+token,TOKEN_CACHE_OLD_TIME,redisAPI.get(TOKEN_KEY_PREFIX+token));
        return newToken;
    }

    // 未考虑移动端
    @Override
    public boolean checkTokenTimeOut(String token, String userAgent) throws Exception {
        // 检查是否存在
        if(redisAPI.exist(TOKEN_KEY_PREFIX+token)){
            // 查看剩余的时间
            Long ttl = redisAPI.ttl(TOKEN_KEY_PREFIX + token);
            // 比较时间是否允许替换(1.5小时之后可以替换)  2 * 60 * 60  - 1.5 * 60 * 60 秒之后
            if(ttl <= TOKEN_REFRESH_TIME){
                return true;
            }
        }
        return false;
    }

    // 单纯保存
    public void saveTokenWithoutDel(String token, ItripUser itripUser, String userAgent){
        // 存储部分用户信息
        ItripUserTokenVO userTokenVO = new ItripUserTokenVO();
        BeanUtils.copyProperties(itripUser,userTokenVO);
        String userTokenJSON = JSON.toJSONString(userTokenVO);
        // 存储Token：移动端永久   PC端两个小时
        if(UserAgentUtil.CheckAgent(userAgent)){
            redisAPI.set(TOKEN_KEY_PREFIX+token,userTokenJSON);
        }else{
            redisAPI.set(TOKEN_KEY_PREFIX+token,TOKEN_TIME_OUT,userTokenJSON);
        }
    }

    @Override
    public void saveToken(String token, ItripUser itripUser, String userAgent) throws Exception {
        // 帐号互斥 顶掉以前登录的信息
        Set<String> tokenSet = checkTokenKeyExists(itripUser, userAgent);
        if(EmptyUtils.isNotEmpty(tokenSet)){
            for (String key : tokenSet) {
                redisAPI.delete(key);
            }
        }
        saveTokenWithoutDel(token,itripUser,userAgent);
    }


    /*
    token 生成算法设计如下：
		例如：PC端：PC-121adv212das-1-201908281128-123456
		PC 端： token:PC-USERCODE[加密]-USERID-CREATIONDATE-RANDEM[6位]
		移 动 端 ： token:MOBILE-USERCODE[加密]-USERID-CREATIONDATE-RANDEM[6位]
     */
    @Override
    public String genToken(ItripUser itripUser, String userAgent) throws Exception {
        StringBuffer tokenStrBuffer = new StringBuffer();
        // 检查是PC端还是移动端
        if(UserAgentUtil.CheckAgent(userAgent)){
            tokenStrBuffer.append(TOKEN_MOBILE_PREFIX);
        }else{
            tokenStrBuffer.append(TOKEN_PC_PREFIX);
        }
        // 加密UserCode
        tokenStrBuffer.append(MD5.getMd5(itripUser.getUserCode(),16)+"-");
        // 用户ID
        tokenStrBuffer.append(itripUser.getId()+"-");
        // 时间戳  20190829095113
        tokenStrBuffer.append(new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) +"-");
        tokenStrBuffer.append(Integer.toString(MD5.getRandomCode()));
        return tokenStrBuffer.toString();
    }
}
